/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights
 * reserved. <a>http://www.cqcis.com</a>
 */
package com.cqcis.uip.base.framework.adaptor;

import java.util.Collection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.SynchronousBundleListener;
import org.osgi.framework.Version;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.osgi.context.DelegatedExecutionOsgiBundleApplicationContext;
import org.springframework.osgi.extender.internal.ContextLoaderListener;
import org.springframework.osgi.extender.internal.support.ApplicationContextConfiguration;
import org.springframework.osgi.extender.internal.util.ConfigUtils;
import org.springframework.osgi.util.OsgiBundleUtils;
import org.springframework.osgi.util.OsgiStringUtils;

import com.cqcis.uip.base.framework.FrameworkConstants;
import com.cqcis.uip.base.framework.core.RegisteredService;
import com.cqcis.uip.base.framework.core.RegisteredServiceFindService;
import com.cqcis.uip.base.framework.core.ResetServiceManage;
import com.cqcis.uip.base.framework.core.ServiceState;
import com.cqcis.uip.base.framework.core.StateManage;
import com.cqcis.uip.base.framework.core.config.impl.PropertiesChgListenerImpl;
import com.cqcis.uip.base.framework.core.impl.ResetServiceManageImpl;
import com.cqcis.uip.base.framework.core.impl.ServiceStateManage;
import com.cqcis.uip.base.framework.core.impl.ServletContainerServerFactory;
import com.cqcis.uip.base.framework.core.service.RegisteredServiceSupport;
import com.cqcis.uip.base.framework.service.EncryptorService;
import com.cqcis.uip.base.framework.service.impl.JasyptEncryptorService;
import com.cqcis.uip.base.framework.service.impl.TelnetConsoleSupport;
import com.cqcis.uip.base.framework.utils.StringUtil;

/**
 * 修改Spring-OSGI服务
 * 
 * @author huangmy
 * @date 2008-3-21
 * 
 * @author liuhz
 * @date 2008-9-22 增加加解密服务注册
 */
public class ContextLoaderListenerAdaptor extends ContextLoaderListener implements CommandProvider {
	private static Log log = LogFactory.getLog(ContextLoaderListenerAdaptor.class);
	private ServiceStateManage ssm = new ServiceStateManage(); // 服务管理
	private Version extenderVersion;
	private TaskExecutor sameThreadTaskExecutor = new SyncTaskExecutor();
	private ServiceRegistration stateManageRegistration; // 服务状态管理注册
	private ServiceRegistration resetServiceManageRegistration; // 服务状态管理注册
	private ServiceRegistration encryptServiceRegistration; // 属性文件加解密
	private BundleContext context; // bundle上下文
	private ServiceRegistration commandRegistration; // 命令注册
	private PropertiesChgListenerImpl propertiesChgListener;
	private TelnetConsoleSupport telnetConsoleSupport; // telnet 服务
	private RegisteredServiceSupport registeredServiceSupport;// 注册服务支持

	/**
	 * 平台事件监听器
	 * 
	 * @author huangmy
	 * @date 2008-4-17
	 */
	private class FrameworkBundleListener implements SynchronousBundleListener {
		public void bundleChanged(BundleEvent event) {
			if (bundleId == event.getBundle().getBundleId()) {
				switch (event.getType()) {
				case BundleEvent.STARTED: {
					maybeCreateApplicationContextFor(event.getBundle());
					log.debug("base-interface bundle started.");
					break;
				}
				case BundleEvent.STOPPING: {
					RegisteredServiceFindService findService = getRegisteredServiceFindService();
					if (findService != null) {
						Collection<RegisteredService> rss = findService.getRegisteredServices();
						if (rss != null) {
							// stop all rs
							for (RegisteredService rs : rss) {
								try {
									rs.stop(rs.getRegisteredServiceContext());
									Bundle bundle = rs.getBundleContext().getBundle();
									maybeCloseApplicationContextFor(bundle); // 关闭上下文
								} catch (Exception e) {
								}
							}
						}
					}
					maybeCloseApplicationContextFor(event.getBundle());
					log.debug("base-interface bundle stopped.");
					break;
				}
				default:
					break;
				}
			}
		}
	}

	/**
	 * 注册服务查找
	 * 
	 * @return
	 */
	private RegisteredServiceFindService getRegisteredServiceFindService() {
		ServiceReference sr = this.context.getServiceReference(RegisteredServiceFindService.class.getName());
		if (sr != null) {
			return (RegisteredServiceFindService) this.context.getService(sr);
		}

		return null;
	}

	@Override
	public void start(BundleContext context) throws Exception {
		context.addBundleListener(new FrameworkBundleListener());
		this.context = context;
		this.extenderVersion = OsgiBundleUtils.getBundleVersion(context.getBundle());
		this.commandRegistration = context.registerService(CommandProvider.class.getName(), this, null);

		this.encryptServiceRegistration = context.registerService(EncryptorService.class.getName(),
				new JasyptEncryptorService(context.getProperty(JasyptEncryptorService.UIP_JASYPT_PASSWORD), context
						.getProperty(JasyptEncryptorService.UIP_JASYPT_PASSWORD_ENV)), null);

		// 注册服务状态管理
		this.stateManageRegistration = context.registerService(StateManage.class.getName(), this.ssm, null);
		this.resetServiceManageRegistration = context.registerService(ResetServiceManage.class.getName(),
				ResetServiceManageImpl.getInstance(), null);

		this.propertiesChgListener = new PropertiesChgListenerImpl();
		this.propertiesChgListener.start(context);

		this.registeredServiceSupport = new RegisteredServiceSupport();
		this.registeredServiceSupport.start(context);

		super.start(context);

		// 启用telnet服务
		this.telnetConsoleSupport = new TelnetConsoleSupport();
		this.telnetConsoleSupport.start(context);
	}

	@Override
	public void stop(BundleContext context) throws Exception {
		if (this.stateManageRegistration != null) {
			this.stateManageRegistration.unregister();
		}

		if (this.registeredServiceSupport != null) {
			this.registeredServiceSupport.stop(context);
		}

		if (this.commandRegistration != null) {
			this.commandRegistration.unregister();
		}

		if (this.encryptServiceRegistration != null) {
			this.encryptServiceRegistration.unregister();
		}

		if (this.resetServiceManageRegistration != null) {
			this.resetServiceManageRegistration.unregister();
		}

		if (this.propertiesChgListener != null) {
			this.propertiesChgListener.stop(context);
		}

		sameThreadTaskExecutor = null;
		// close spring context
		maybeCloseApplicationContextFor(context.getBundle());

		if (this.telnetConsoleSupport != null) {
			this.telnetConsoleSupport.stop(context);
		}

		super.stop(context);
		
		ServletContainerServerFactory.getInstance().destoryAll();
	}

	/**
	 * 创建应用上下文
	 */
	@Override
	protected DelegatedExecutionOsgiBundleApplicationContext createApplicationContext(BundleContext context,
			String[] locations) {
		OsgiBundleXmlApplicationContextAdaptor sdoac = null;
		try {
			sdoac = new OsgiBundleXmlApplicationContextAdaptor(locations, ssm, this.context.getBundle());
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}

		sdoac.setBundleContext(context);
		super.postProcessContext(sdoac);

		return sdoac;
	}

	@Override
	protected synchronized void maybeCloseApplicationContextFor(Bundle bundle) {
		super.maybeCloseApplicationContextFor(bundle);

		ssm.remove(bundle.getBundleId());// delete
	}

	@SuppressWarnings("unchecked")
	protected synchronized void maybeCreateApplicationContextFor(Bundle bundle) {
		if (!ConfigUtils.matchExtenderVersionRange(bundle, extenderVersion)) {
			if (log.isDebugEnabled())
				log.debug("Bundle [" + OsgiStringUtils.nullSafeNameAndSymName(bundle)
						+ "] expects an extender w/ version["
						+ OsgiBundleUtils.getHeaderAsVersion(bundle, ConfigUtils.EXTENDER_VERSION)
						+ "] which does not match current extender w/ version[" + extenderVersion
						+ "]; skipping bundle from context creation");
			return;
		}

		ApplicationContextConfiguration config = new ApplicationContextConfiguration(bundle);
		if (log.isDebugEnabled()) {
			log.debug("Created config " + config);
		}
		
		boolean executeContinued = true;
		if (bundle.getLocation().endsWith(".war")) { // webapp
			executeContinued = false;
			config = new ApplicationContextConfiguration(bundle) {
				@Override
				public String[] getConfigurationLocations() {
					String[] configs = new String[] {FrameworkConstants.ROLE_WEBAPP_CONFIG};
					return configs;
				}
			};
		}

		if (!config.isSpringPoweredBundle() && executeContinued) {
			return;
		}

		Long bundleId = new Long(bundle.getBundleId());

		final DelegatedExecutionOsgiBundleApplicationContext context = createApplicationContext(OsgiBundleUtils
				.getBundleContext(bundle), config.getConfigurationLocations());

		if (managedContexts.containsKey(bundleId)) {
			if (log.isDebugEnabled()) {
				log.debug("Bundle is already under control: " + bundle.getSymbolicName());
			}
			return;
		}
		managedContexts.put(bundleId, context);

		context.setPublishContextAsService(config.isPublishContextAsService());

		Runnable contextRefresh = new Runnable() {
			public void run() {
				context.refresh();
			}
		};

		TaskExecutor executor = null;

		// 同步创建上下文
		if (config.isCreateAsynchronously()) {
			if (log.isDebugEnabled()) {
				log.debug("Asynchronous context creation for bundle " + OsgiStringUtils.nullSafeNameAndSymName(bundle));
			}
			// for the async stuff use the executor
			executor = taskExecutor;
		} else {
			if (log.isDebugEnabled()) {
				log.debug("Synchronous context creation for bundle " + OsgiStringUtils.nullSafeNameAndSymName(bundle));
			}
			// for the sync stuff, use this thread
			executor = sameThreadTaskExecutor;
		}

		// 等待依赖行为
		if (config.isWaitForDependencies()) {// 修改原有方法，增加状态管理
			DependencyWaiterApplicationContextExecutorAdaptor appCtxExecutor = new DependencyWaiterApplicationContextExecutorAdaptor(
					context, !config.isCreateAsynchronously(), ssm);

			bundle = context.getBundle();
			ssm.addState(bundle.getBundleId(), new ServiceState(bundle,
					appCtxExecutor));

			appCtxExecutor.setTimeout(config.getTimeout());
			appCtxExecutor.setWatchdog(timer);
			appCtxExecutor.setTaskExecutor(executor);
			appCtxExecutor.setMonitoringCounter(contextsStarted);

			contextsStarted.increment();
		} else {
			// do nothing; by default contexts do not wait for services.
		}

		executor.execute(contextRefresh);
	}

	/**
	 * 启动spring服务
	 * 
	 * @param ci
	 */
	public void _sstart(CommandInterpreter ci) {
		Bundle bundle = getBundleFromCI(ci);
		if (bundle != null) {
			maybeCreateApplicationContextFor(bundle);
		}
	}

	/**
	 * 重启
	 * 
	 * @param ci
	 */
	public void _restart(CommandInterpreter ci) {
		Bundle bundle = getBundleFromCI(ci);
		if (bundle != null) {
			try {
				bundle.stop();
				maybeCloseApplicationContextFor(bundle);
				try {
				    Thread.sleep(2000);
				} catch (Exception e) {
				}
				bundle.start();
				maybeCreateApplicationContextFor(bundle);
			} catch (Exception e) {
			}
		}
	}

	/**
	 * 停止spring服务
	 * 
	 * @param ci
	 */
	public void _sstop(CommandInterpreter ci) {
		Bundle bundle = getBundleFromCI(ci);
		if (bundle != null) {
			maybeCloseApplicationContextFor(bundle);
		}
	}

	public String getHelp() {
		StringBuffer buffer = new StringBuffer();
		return buffer.toString();
	}

	private Bundle getBundleFromCI(CommandInterpreter ci) {
		String idStr = ci.nextArgument();
		idStr = StringUtil.trimWhiteToNull(idStr);
		if (idStr == null) {
			ci.print("WARN: id is needed.");
			return null;
		}

		long id = Long.parseLong(idStr);
		return this.context.getBundle(id);
	}
}
